package personal.lijun.skeleton.web.access.intercept;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;
import personal.lijun.skeleton.web.access.expression.CustomWebSecurityExpressionHandler;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * @Auther: lijun@sstcsoft.com
 * @Date: 2019/9/18 16:47
 */
@Component("filterInvocationServiceSecurityMetadataSource")
public class FilterInvocationServiceSecurityMetadataSource implements
        FilterInvocationSecurityMetadataSource, InitializingBean {

    @Autowired
    private RequestConfigMappingService requestConfigMappingService = null;

    @Autowired
    private CustomWebSecurityExpressionHandler expressionHandler;

    private ExpressionBasedFilterInvocationSecurityMetadataSource delegate;
    @Override
    public void afterPropertiesSet() throws Exception {
        List<RequestConfigMapping> requestConfigMappings =
                requestConfigMappingService.getRequestConfigMappings();
        LinkedHashMap requestMap = new
                LinkedHashMap(requestConfigMappings.size());
        for(RequestConfigMapping requestConfigMapping :
                requestConfigMappings) {
            RequestMatcher matcher =
                    requestConfigMapping.getMatcher();
            Collection<ConfigAttribute> attributes =
                    requestConfigMapping.getAttributes();
            requestMap.put(matcher,attributes);
        }
        this.delegate =
                new
                        ExpressionBasedFilterInvocationSecurityMetadataSource
                        (requestMap,expressionHandler);
    }

    /**
     * Accesses the {@code ConfigAttribute}s that apply to a given secure object.
     *
     * @param object the object being secured
     * @return the attributes that apply to the passed in secured object. Should return an
     * empty collection if there are no applicable attributes.
     * @throws IllegalArgumentException if the passed object is not of a type supported by
     *                                  the <code>SecurityMetadataSource</code> implementation
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        return this.delegate.getAttributes(object);
    }

    /**
     * If available, returns all of the {@code ConfigAttribute}s defined by the
     * implementing class.
     * <p>
     * This is used by the {@link AbstractSecurityInterceptor} to perform startup time
     * validation of each {@code ConfigAttribute} configured against it.
     *
     * @return the {@code ConfigAttribute}s or {@code null} if unsupported
     */
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return this.delegate.getAllConfigAttributes();
    }

    /**
     * Indicates whether the {@code SecurityMetadataSource} implementation is able to
     * provide {@code ConfigAttribute}s for the indicated secure object type.
     *
     * @param clazz the class that is being queried
     * @return true if the implementation can process the indicated class
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return this.delegate.supports(clazz);
    }
}
